#include <buola/config.h>

#ifdef BUOLA_HAVE_PULSE

#include <blackbox/blackbox.h>

#include "cpulsecontext.h"
#include "cpulsestream.h"
#include "cpulseloop.h"

namespace buola { namespace media { namespace pulse {

static void stream_state_callback(pa_stream *pS,void *pPS)
{
    CPulseStream *lPS=reinterpret_cast<CPulseStream*>(pPS);

    lPS->GetContext().GetLoop().Signal();
}

CPulseStream::CPulseStream(CPulseContext &pCtx,const std::string &pName,int pRate,int pChannels,
                                             pa_sample_format_t pFormat)
    :   mCtx(pCtx)
{
    pa_sample_spec lSS;

    lSS.format=pFormat;
    lSS.channels=pChannels;
    lSS.rate=pRate;

    CPulseLock lLock(mCtx.GetLoop());
    mStream=pa_stream_new(pCtx.mCtx,pName.c_str(),&lSS,nullptr);
    pa_stream_set_state_callback(mStream,stream_state_callback,this);
}

CPulseStream::~CPulseStream()
{
    CPulseLock lLock(mCtx.GetLoop());
    pa_stream_unref(mStream);
}

void CPulseStream::ConnectPlayback()
{
    CPulseLock lLock(mCtx.GetLoop());
    pa_stream_connect_playback(mStream,nullptr,nullptr,PA_STREAM_NOFLAGS,nullptr,nullptr);
}

void CPulseStream::Write(const void *pData,std::size_t pSize)
{
    CPulseLock lLock(mCtx.GetLoop());
    const uint8_t *lData=(const uint8_t*)pData;

    while(pSize)
    {
        std::size_t lWritable=pa_stream_writable_size(mStream);

        std::size_t lToWrite=min(pSize,lWritable);

        pa_stream_write(mStream,lData,lToWrite,nullptr,0,PA_SEEK_RELATIVE);
        mCtx.GetLoop().Unlock();
        sleep(5_ms);
        mCtx.GetLoop().Lock();

        pSize-=lToWrite;
        lData+=lToWrite;
    }
}

bool CPulseStream::WaitForConnection()
{
    CPulseLock lLock(mCtx.GetLoop());
    while(true)
    {
        pa_stream_state_t lState=pa_stream_get_state(mStream);

        if(lState==PA_STREAM_READY)
            return true;
        else if(lState==PA_STREAM_FAILED||lState==PA_STREAM_TERMINATED)
            return false;

        mCtx.GetLoop().Wait();
    }
}

/*namespace pulse*/ } /*namespace media*/ } /*namespace buola*/ }

#endif //BUOLA_HAVE_PULSE
